using System;
using System.Configuration;
using System.Drawing;
using System.IO;

namespace ClickNET
{
    public class ImageResize
    {
		private double          m_width, 
                                m_height, 
                                m_dimensions;
		private bool            m_use_aspect            = true;
        private bool            m_use_longest_dimension = true;
		private string          m_image_path;
		private Image           m_src_image, m_dst_image;
		private ImageResize     m_cache;
		private Graphics        m_graphics;

		public string File
		{
			get { return m_image_path; }
			set { m_image_path = value; }
		}

		public Image Image
		{
			get { return m_src_image; }
			set { m_src_image = value; }
		}

		public bool PreserveAspectRatio
		{
			get { return m_use_aspect; }
			set { m_use_aspect = value; }
		}

        public bool UseLongestDimension
        {
            get { return m_use_longest_dimension; }
            set { m_use_longest_dimension = value; }
        }

		public double Width
		{
			get { return m_width; }
			set { m_width = value; }
		}

        public double Height
        {
            get { return m_height; }
            set { m_height = value; }
        }

        public double Size
        {
            get { return m_dimensions; }
            set { m_dimensions = value; }
        }

		protected virtual bool IsSameSrcImage(ImageResize other)
		{
			if (other != null)
			{
				return (File == other.File
					&& Image == other.Image);
			}
		
			return false;
		}

		protected virtual bool IsSameDstImage(ImageResize other)
		{
			if (other != null)
			{
				return (Width == other.Width 
					&& Height == other.Height
                    && PreserveAspectRatio == other.PreserveAspectRatio);
            }

            return false;
        }

        public virtual Image GetThumbnail()
        {
            // Flag whether a new image is required
            bool recalculate = false;
            double new_width = Width;
            double new_height = Height;

            // Is there a cached source image available? If not,
            // load the image if a filename was specified; otherwise
            // use the image in the Image property
            if (!IsSameSrcImage(m_cache))
            {
                if (!String.IsNullOrEmpty(this.m_image_path))
                {
                    
					// Load via stream rather than Image.FromFile to release the file
					// handle immediately
					if (m_src_image != null)
						m_src_image.Dispose();

					// Wrap the FileStream in a "using" directive, to ensure the handle
					// gets closed when the object goes out of scope
					using(Stream stream = new FileStream(m_image_path, FileMode.Open, FileAccess.Read))
						m_src_image = Image.FromStream(stream);
                }
            }

            // Use this to specify a single largest dimension and that will be the basis
            // for creating a thumbnail
            if (UseLongestDimension)
            {
                if ((double)m_src_image.Width >= (double)m_src_image.Height)
                {
                    new_width = Size;
                    Width = Size;
                }
                else
                {
                    new_height = Size;
                    Height = Size;
                }

            }

            // Check whether the required destination image properties have
            // changed
            if (!IsSameDstImage(m_cache))
            {
                // If you specified an aspect ratio and absolute width or height, then calculate this 
                // now; if you accidentally specified both a width and height, ignore the 
                // PreserveAspectRatio flag
                if (PreserveAspectRatio)
                {
                    if (Width != 0 && Height == 0)
                    {
                        new_height = (Width / (double)m_src_image.Width) * m_src_image.Height;
                    }
                    else if (Height != 0 && Width == 0)
                    {
                        new_width = (Height / (double)m_src_image.Height) * m_src_image.Width;
                    }
                }
            }

            recalculate = true;

            if (recalculate)
            {
                // Calculate the new image
                if (m_dst_image != null)
                {
                    m_dst_image.Dispose();
                    m_graphics.Dispose();
                }
                // Render using high quality interpolation to make up for GDI's shitty quality
                Bitmap bitmap = new Bitmap((int)new_width, (int)new_height, m_src_image.PixelFormat);
                m_graphics = Graphics.FromImage(bitmap);
                m_graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                m_graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

                // hack to fix the 1px border issue (-1 +1)
                m_graphics.DrawImage(m_src_image, -1, -1, bitmap.Width + 1, bitmap.Height + 1);
                m_dst_image = bitmap;

                // Cache the image and its associated settings
                m_cache = this.MemberwiseClone() as ImageResize;
            }

            return m_dst_image;
        }

        public string Dimensions(string path)
        {
            System.IO.FileInfo fi = new System.IO.FileInfo(path);
            ImageResize o = new ImageResize();

            String Directory = fi.DirectoryName;
            String Name = fi.Name;
            this.File = Directory + "\\" + Name;

            if (!String.IsNullOrEmpty(this.m_image_path))
            {
				// Load via stream rather than Image.FromFile to release the file
                // handle immediately
                if (m_src_image != null)
                    m_src_image.Dispose();

                // Wrap the FileStream in a "using" directive, to ensure the handle
                // gets closed when the object goes out of scope
                using (Stream stream = new FileStream(m_image_path, FileMode.Open, FileAccess.Read))
                {
                    m_src_image = Image.FromStream(stream);
                }
            }

            return m_src_image.Width.ToString() + "x" + m_src_image.Height.ToString();
        }

        ~ImageResize()
        {
            // Free resources
            if (m_dst_image != null)
            {
                m_dst_image.Dispose();
                m_graphics.Dispose();
            }

            if (m_src_image != null)
                m_src_image.Dispose();
        }
    }
}
